package culosic.mdpocket.html;

import java.util.*;
import java.util.regex.*;
import culosic.mdpocket.core.*;

public class TransHtml implements Trans {

	protected enum Type {
		Set, Insert, Delete
	};

	/*
	 * 改变产生的数据
	 */
	protected class LineSet implements Change {
		protected int lineNumber;
		protected String data;
		protected Type type;

		public LineSet(Type type, int lineNumber, String data) {
			this.type = type;
			this.lineNumber = lineNumber;
			this.data = data;
		}
	}

	// 源文档
	private ArrayList<String> lines = null;
	// 文档父节点栈
	private Stack<Node> root = new Stack<>();

	// 工厂
	private HtmlFactory factory = new HtmlFactory();
	// 输出
	public HtmlOut out = null;

	public TransHtml(ArrayList<String> lines, String css) {
		this.lines = lines;
		out = new HtmlOut(css);
	}

	private final static Pattern h = Pattern.compile("^(#{1,6})\\s?((?:\\\\#|[^#])+)(?:\\s+#+)?");

	private final static Pattern pre = Pattern.compile("^\\s*`{3}\\s*(.*)$");

	private final static Pattern preEnd = Pattern.compile("^\\s*`{3}\\s*$");

	private final static Pattern title = Pattern.compile("^\\s*(={2,})|(-{2,})\\s*$");

	private final static Pattern aUse = Pattern.compile("^\\s*(!)?\\[(.+?)(?<!\\\\)\\]\\s*\\[(.+?)(?<!\\\\)\\]",
			Pattern.CASE_INSENSITIVE);

	private final static Pattern aDefine = Pattern.compile(
		"^\\s*(!)?\\[(.+)(?<!\\\\)\\]\\s*:\\s*(<)?([^>]+)((?<!\\\\)>)?(\\s+((?:\"|'|\\()(.+)(?:\"|'|\\()))?$",
			Pattern.CASE_INSENSITIVE);

	private final static Pattern aDefineT = Pattern.compile("^\\s*((?:\"|'|\\().+(?:\"|'|\\())\\s*$", Pattern.CASE_INSENSITIVE);

	/**
	 * 初始化
	 */
	private void solveInit() {
		// 初始化文档节点
		if (!root.isEmpty()) {
			root.peek().clear();
			root.clear();
		}
		root.push(factory.createRoot());
	}

	@Override
	public void solve() {
		Node n = null;
		boolean found;
		int i = 0, j = 0; // i：行，j：临时变量
		int di; // 查找返回结果，用于跟i比对判断是否找到

		// 参考式链接和图片存放
		List<String> aUseId = new ArrayList<>();
		List<NodeA> aUseNode = new ArrayList<>();
		List<String> imgUseId = new ArrayList<>();
		List<NodeImg> imgUseNode = new ArrayList<>();

		List<String> defineId = new ArrayList<>();
		List<String> defineHref = new ArrayList<>();
		List<String> defineTitle = new ArrayList<>();
		List<String> defineType = new ArrayList<>();

		// 初始化
		solveInit();

		// 解析
		while (i < lines.size()) {
			String line = lines.get(i);
			Matcher m;

			/*************** 栈格式 ***************/

			// 引用
			line = solveBlockquote(line);
			System.out.println(line + ": " + root.peek());

			/*************** 非栈格式 ***************/

			// 分割线
			di = solveHr(i, line);
			if (i != di) {
				i = di;
				continue;
			}

			// 查找标题
			m = h.matcher(line);
			if (m.find()) {
				n = factory.createNodeH(m.group(1).length());
				root.peek().appendChild(n);
				solveInline(n, m.group(2));
				i++;
				continue;
			}

			// 查找列表
			di = solveList(i, line, lines);
			if (i != di) {
				i = di;
				continue;
			}

			// 表格
			di = solveTable(i, line);
			if (i != di) {
				i = di;
				continue;
			}

			// 代码块
			boolean over = false;
			m = pre.matcher(line);
			if (m.find()) {
				n = factory.createNodePre(m.group(1));
				root.peek().appendChild(n);
				do {
					i++;
					if (i <= lines.size() - 1) {
						line = lines.get(i);
						m = preEnd.matcher(line);
						if (!m.find()) {
							n.appendChild(factory.createNodeText(line + "\n"));
						} else {
							over = true;
						}
					} else {
						over = true;
					}
				} while (!over);
				i++;
				continue;
			}

			// 第二种标题
			found = false;
			if (i + 1 < lines.size()) {
				m = title.matcher(lines.get(i + 1));
				if (m.find()) {
					n = factory.createNodeH(m.group(1) != null ? 1 : 2);
					solveInline(n, line);
					root.peek().appendChild(n);
					found = true;
				}
			}
			if (found) {
				i += 2;
				continue;
			}

			// 换行
			di = solveBr(i, line);
			if (i != di) {
				i = di;
				continue;
			}

			// 定义式链接和图片使用
			m = aUse.matcher(line);
			if (m.find()) {
				if (m.group(1) != null) {
					n = factory.createNodeImg("(等待填入)", m.group(2));
					root.peek().appendChild(n);
					imgUseId.add(m.group(3));
					imgUseNode.add((NodeImg) n);
				} else {
					n = factory.createNodeA("(等待填入)");
					n.appendChild(factory.createNodeText(m.group(2)));
					root.peek().appendChild(n);
					aUseId.add(m.group(3));
					aUseNode.add((NodeA) n);
				}
				i++;
				continue;
			}
			// 定义式链接和图片声明
			m = aDefine.matcher(line);
			if (m.find()) {
				found = false;
				if (m.group(8) != null) {
					defineTitle.add(m.group(8));
					found = true;
				} else if (i + 1 < lines.size()) {
					// 探寻下一行
					Matcher mm = aDefineT.matcher(lines.get(i + 1));
					if (mm.find()) {
						defineTitle.add(mm.group(1));
						found = true;
						i++;
					}
				}
				if (!found) {
					defineTitle.add(null);
				}
				defineId.add(m.group(2));
				defineHref.add(m.group(4));
				if (m.group(1) != null) {
					defineType.add("img");
				} else {
					defineType.add("a");
				}
				i++;
				continue;
			}

			// 普通整行文本
			solveInline(root.peek(), line);
			i++;
		}

		// 填入定义式链接和图片
		for (j = 0; j < defineId.size(); j++) {
			for (i = 0; i < aUseId.size(); i++) {
				if (aUseId.get(i).toLowerCase().equals(defineId.get(j).toLowerCase())
						&& "a".equals(defineType.get(j))) {
					NodeA a = aUseNode.get(i);
					a.set(defineHref.get(j), defineTitle.get(j));
				}
			}
			for (i = 0; i < imgUseId.size(); i++) {
				if (imgUseId.get(i).toLowerCase().equals(defineId.get(j).toLowerCase())
						&& "img".equals(defineType.get(j))) {
					NodeImg img = imgUseNode.get(i);
					img.set(defineHref.get(j), defineId.get(j));
				}
			}
		}

	}

	private final static Pattern blockquote = Pattern.compile("^\\s*((?:>\\s*)+)(.*)");

	// <blockquote>
	private String solveBlockquote(String line) {
		Matcher m = blockquote.matcher(line);
		boolean found = m.find();
		int s1 = 0;
		Stack<Node> rootP = new Stack<>();
		boolean ok = true;
		if (found) {
			s1 = m.group(1).replaceAll("\\s", "").length();
		}
		// 倒栈
		while (ok) {
			if (root.peek() instanceof NodeBlockQuote) {
				rootP.push(root.pop());
			} else {
				ok = false;
			}
		}
		int s2 = rootP.size();

		// 复原
		while (!rootP.isEmpty()) {
			root.push(rootP.pop());
		}

		// 新增了引用层次
		System.out.println(String.format("s1=%d, s2=%d\n", s1, s2));
		while (s1 > s2) {
			Node node = factory.createNodeBlockquote();
			root.peek().appendChild(node);
			root.push(node);
			s2++;
		}

		// 降低了引用层次
		while (s1 < s2) {
			root.pop();
			s2--;
		}
		return found ? m.group(2) : line;
	}

	private final static Pattern table = Pattern.compile("^([^\\|]|\\\\\\|)*(?<!\\\\)\\|.*$");

	private final static Pattern th = Pattern.compile("^(-{2,}\\s*\\|\\s*(-{2,})?)+\\s*$");

	// <table> <tr> <th> <td>
	private int solveTable(int i, String line) {
		Stack<Node> stack = null;
		int ths = 0;
		if (table.matcher(line).find()) {
			stack = new Stack<>();
			stack.push(factory.createNodeTable());
			root.peek().appendChild(stack.peek());
			// 匹配
			while (table.matcher(line).find()) {
				// 不够分割退出
				String[] tds = line.split("(?<!\\\\)\\|");
				if (tds.length <= 0) {
					break;
				}

				// 添加th标记
				ths = -1;
				if (i + 1 < lines.size() && th.matcher(lines.get(i + 1)).find()) {
					ths = lines.get(i + 1).split("(?<!\\\\)\\|").length;
				}

				// tr入栈，添加tr
				Node n = factory.createNodeTr();
				stack.peek().appendChild(n);
				stack.push(n);
				for (String td : tds) {
					if (ths > 0) {
						// th
						ths--;
						n = factory.createNodeTh();
						n.appendChild(factory.createNodeText(td));
						stack.peek().appendChild(n);
					} else {
						// td
						n = factory.createNodeTd();
						n.appendChild(factory.createNodeText(td));
						stack.peek().appendChild(n);
					}
				}
				// tr出栈
				stack.pop();
				// 到底了，退出
				int j = (ths == -1 ? 1 : 2);
				i += j;
				if (i >= lines.size()) {
					break;
				}
				line = lines.get(i);
			}
		}
		return i;
	}

	private final static Pattern hr = Pattern.compile("^\\s*((?<!\\\\)(\\*|-|_)\\s*){3,}\\s*$");

	// <hr>
	private int solveHr(int i, String line) {
		Matcher m = hr.matcher(line);
		if (m.find()) {
			root.peek().appendChild(factory.createNodeTextNoParse("<hr>"));
			i++;
		}
		return i;
	}

	private final static Pattern br = Pattern.compile("^\\s*$");

	private final static Pattern br2 = Pattern.compile("\\s{2}$");

	// <br>
	private int solveBr(int i, String line) {
		Matcher m = br.matcher(line);
		if (m.find()) {
			if (root.peek().getChilds().size() <= 0
					|| root.peek().getChilds().get(root.peek().getChilds().size() - 1) instanceof NodeText) {
				root.peek().appendChild(factory.createNodeTextNoParse("<br>"));
			} else {
				root.peek().appendChild(factory.createNodeText("\n"));
			}
			i++;
		} else if (i - 1 >= 0) {
			m = br2.matcher(lines.get(i - 1));
			if (m.find()) {
				root.peek().appendChild(factory.createNodeTextNoParse("<br>"));
			}
		}
		return i;
	}

	private final static Pattern list = Pattern
			.compile("^((\\s*)(?:(?<!\\\\)-|(?<!\\\\)\\*|(?<!\\\\)\\+)\\s(.*))|((\\s*)\\d(?<!\\\\)\\.\\s(.*))$");

	// list <ul> <ol> <li>
	private int solveList(int i, String line, ArrayList<String> lines) {
		Node n = null;
		Stack<Node> stack = null;
		Matcher m = list.matcher(line);
		if (m.find()) {
			stack = new Stack<>();
			stack.push(root.peek());
		}
		int level = -1;
		int gSpace, gLi;
		int levelNow;
		while (m.find(0) && i < lines.size()) {
			gSpace = (m.group(1) != null ? 2 : 5);
			gLi = (m.group(1) != null ? 3 : 6);
			levelNow = m.group(gSpace).replace("\t", " ").length() / 4;
			// 无序表或有序表
			if (levelNow > level) {
				// 升级 最多升1级
				level++;
				n = (m.group(1) != null ? factory.createNodeUl() : factory.createNodeOl());
				stack.peek().appendChild(n);
				stack.push(n);
			} else if (levelNow <= level) {
				// 降级 最多到1级
				int levelD = levelNow;
				while (levelD < level && stack.size() > 2) {
					stack.pop();
					level--;
				}
			}
			// 添加li
			n = factory.createNodeLi();
			solveInline(n, m.group(gLi));
			stack.peek().appendChild(n);
			i++;
			if (i <= lines.size() - 1) {
				line = lines.get(i);
				m = list.matcher(line);
			}
		}
		return i;
	}

	/*
	 * ^ 1( (?:\\s*) 2( (?<!\\\\)- | (?<!\\\\)\\* | (?<!\\\\)\\+ ) 3\\s(.*) ) | 4(
	 * 5(\\s*) \\d (?<!\\\\)\\. \\s 6(.*) ) $
	 */

	private final static Pattern inline = Pattern.compile("((?<!\\\\)\\*{1,3}" + "|(?<!\\\\)_{1,3})\\s*(.+?)\\s*\\1"
			+ "|((?<!\\\\)!)?(?<!\\\\)\\[(.+?)(?<!\\\\)\\](?<!\\\\)\\(\\s*(.+?)(\\s+\"(.+?)\")?\\s*(?<!\\\\)\\)"
			+ "|(?<!\\\\)`{1,2}(.+?)(?<!\\\\)`{1,2}");

	private void solveInline(Node parent, String str) {
		boolean found = false;
		Node n = null;
		Matcher m = inline.matcher(str);
		String[] p = inline.split(str);
		int pRemain = p.length;

		// group !3[4](5 "6"7) ``8``
		final int a_href = 5, a_title = 7, a_txt = 4;
		final int img_alt = 4, img_src = 5, img_title = 7;
		final int is_img = 3, is_a_img = 4;

		// 循环匹配
		for (int i = 0; m.find(); i++) {
			if (!found) {
				found = true;
			}
			if (i < p.length) {
				pRemain--;
				n = factory.createNodeText(p[i]);
				parent.appendChild(n);
			}
			if (m.group(1) != null) {
				switch (m.group(1).length()) {
				case 1: // 斜体
					n = factory.createNodeEm();
					break;
				case 2: // 加粗
					n = factory.createNodeStrong();
					break;
				case 3: // 粗斜体
					n = factory.createNodeEmStrong();
					break;
				default:
					n = factory.createNodeText("(inline匹配长度超出的错误节点)");
				}
				n.appendChild(factory.createNodeText(m.group(2)));
				parent.appendChild(n);
			} else if (m.group(is_a_img) != null) {
				// 行内链接和图片
				if (m.group(is_img) == null) {
					if (m.group(a_title) != null) {
						n = factory.createNodeA(m.group(a_href), m.group(a_title));
						n.appendChild(factory.createNodeText(m.group(a_txt)));
					} else {
						n = factory.createNodeA(m.group(a_href));
						n.appendChild(factory.createNodeText(m.group(a_txt)));
					}
				} else {
					if (m.group(img_title) != null) {
						n = factory.createNodeImg(m.group(img_src), m.group(img_alt), m.group(img_title));
					} else {
						n = factory.createNodeImg(m.group(img_src), m.group(img_alt));
					}
				}
				parent.appendChild(n);
			}
			// 代码串<code>
			else if (m.group(8) != null) {
				n = factory.createNodeCode();
				n.appendChild(factory.createNodeText(m.group(8)));
				parent.appendChild(n);
			} else {
				System.out.println("(inline匹配到的错误节点)");
			}
		}
		// 结尾非匹配字符
		if (p.length > 1 && pRemain > 0) {
			n = factory.createNodeText(p[p.length - 1]);
			parent.appendChild(n);
		}
		// 完全未匹配到
		if (!found) {
			n = factory.createNodeText(str);
			parent.appendChild(n);
		}
	}

	@Override
	public void showOn() {
		out.clear();
		root.peek().show(out);
	}

}
